<html>
<head>
<title>CpcPaChi - Version 0.15</title>
<style type="text/css">
span {
    font-family: 'Courier New';
    font-size: 10pt;
    color: #000000;
}
.sc0 {
    color: #808080;
}
.sc3 {
    color: #008080;
}
.sc4 {
    color: #FF8000;
}
.sc5 {
    font-weight: bold;
    color: #0000FF;
}
.sc7 {
    color: #808080;
}
.sc9 {
    color: #804000;
}
.sc10 {
    font-weight: bold;
    color: #000080;
}
.sc11 {
}
</style>
</head>
<body>
<h2>Un compilador sencillo paso a paso (15 - Peque&ntilde;as mejoras: Token, WriteString, CpcInk)</h2>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>

<p>Nuestro analizador l&eacute;xico tiene todav&iacute;a varias carencias. Posiblemente
una de las m&aacute;s importantes es que los identificadores pueden
estar formados por varias letras, pero los operadores no,
por lo que todav&iacute;a no podemos reconocer comparaciones como
&quot;&lt;=&quot;.</p>

<p>Para solucionarlo, tenemos dos alternativas. La r&aacute;pida pero mala
es permitir que los &quot;s&iacute;mbolos&quot; est&eacute;n formados por
m&aacute;s de un car&aacute;cter. La correcta es empezar a hablar
(por fin) de &quot;tokens&quot;. As&iacute;,  tanto &quot;if&quot; como
&quot;+&quot; o &quot;&lt;=&quot; o la variable &quot;x&quot;
ser&iacute;an tokens, cada uno de ellos con un &quot;valor&quot; o
&quot;lexema&quot; y tambi&eacute;n con un &quot;tipo&quot; (junto con
otros datos que nos pueden ser &uacute;tiles, como la fila y columna
en que se encuentra). En esta entrega, crearemos la clase Token, y a&ntilde;adiremos
un &quot;ObtenerToken&quot; a nuestro Scanner, que se encargue de generar Tokens
distintos a partir de secuencias como &lt;, &lt;= o &lt;&gt;, as&iacute;:</p>

<pre><code>
case '(': lexema = &quot;&quot;+letra; tipo = tToken.PARI; break;
case ')': lexema = &quot;&quot;+letra; tipo = tToken.PARD; break;
case ';': lexema = &quot;&quot;+letra; tipo = tToken.PYC; break;
case ':':
      char letra2 = ObtenerLetra();
      if (letra2 == '=')
      {
          lexema = &quot;:=&quot;;
          tipo = tToken.ASIGN;
          break;
      }
      else
      {
          lexema = &quot;&quot;+letra; tipo =
          tToken.DOSP;
          break;
      }
...
</code></pre>

<p>Adem&aacute;s, orientado a la m&aacute;quina de destino a&ntilde;adiremos
una orden cpcInk, que permita jugar con la paleta de colores,
redefinir color haciendo cpcInk(1,WHITE); o bien cpcInk(1,BLUE, RED);
(este &uacute;ltimo formato parpadear&iacute;a entre dos colores).
Estas constantes para los colores estar&aacute;n definidas tambi&eacute;n
en el compilador, para que el c&oacute;digo sea m&aacute;s legible.</p>

<p>Definir las constantes es sencillo: las introducimos directamente en nuestra
tabla de s&iacute;mbolos:</p>

<pre><code>
miTablaSimb.Insertar("BLACK", tipoId.CONST, tamDato.BYTE,0);
miTablaSimb.Insertar("BLUE", tipoId.CONST, tamDato.BYTE,1);
miTablaSimb.Insertar("LIGHTBLUE", tipoId.CONST, tamDato.BYTE,2);
miTablaSimb.Insertar("RED", tipoId.CONST, tamDato.BYTE,3);
</code></pre>

<p>En cuanto a la orden CPCINK, apenas tiene dos peque&ntilde;as dificultades:
la primera es puede tener dos par&aacute;metros (tinta y color) o tres
(para que parpadee entre dos colores), de modo que tendremos
que preverlo en el analizador sint&aacute;tico:</p>

<pre><code>
string color1 = miScanner.ObtenerEnteroOIdentificador();
char separador = miScanner.LeerCualquierSimbolo();
string color2;
if (separador == ',')
{
  color2 = miScanner.ObtenerEnteroOIdentificador();
}
else
{
  color2 = color1;
  miScanner.Retroceder();
}
miScanner.LeerSimbolo(')');
miScanner.LeerSimbolo(';');
...
</code></pre>

<p>La segunda peque&ntilde;a complicaci&oacute;n es que la secuencia
en c&oacute;digo m&aacute;quina equivalente usa los registros B y C,
y nuestra lectura de valores enteros o en la tabla de
s&iacute;mbolos se basa en el registro A. Podemos crear nuevas
funciones de b&uacute;squeda, o simplemente obtener el resultado
en A y volcarlo a B o C posteriormente, algo que supone
desperdiciar dos bytes. Si optamos por esta soluci&oacute;n,
tendr&iacute;amos algo como:</p>

<pre><code>
GenLecturaValor( color1 );
// Copio el primer color de A a B
ficheroDestino.WriteLine(lineaActual+" DATA 47: ' LD B, A" );
lineaActual += 10;

GenLecturaValor( color2 );
// Copio el segundo color de A a C
ficheroDestino.WriteLine(lineaActual+" DATA 4F: ' LD C, A" );
lineaActual += 10;

// Y guardo la tinta en A
GenLecturaValor( tinta );

ficheroDestino.WriteLine(lineaActual+
    " DATA CD,32,BC: ' CALL &BC32 - SET INK" );
</code></pre>


<p>Tambi&eacute;n a&ntilde;adiremos una orden WriteString, que escriba una cadena
(prefijada) en vez de s&oacute;lo una letra. La dificultad de esta orden es que en
el CPC no existe una orden para escribir una cadena en c&oacute;digo m&aacute;quina, por lo
que tenemos que iterar para escribirla car&aacute;cter a car&aacute;cter. Una forma
sencilla de conseguirlo es a&ntilde;adir un caracter 0 al final, como marca de fin
de cadena</p>

<pre><code>
LD DE, direccionTexto
LD A, (DE)
OR A
JP Z, direccionSalida
CALL &amp;BB5A - WRITECHAR
INC DE
JP direccionRepetir
</code></pre>

<p>Ahora podremos hacer cosas como:</p>

<pre><code>program ej15a; { Ejemplo 15a de CpcPaChi }

var
  fila: byte;

begin
  CpcMode(2);
  CpcInk(1,WHITE);
  fila := 3;
  locate(2,fila);
  writeString('Hola Mundo');
end.
</code></pre>


<p>que dar&iacute;a como resultado:</p>

<img src="ej015a.png" alt="eemplo15a" />

<p>O bien como:</p>

<pre><code>program ej15; { Ejemplo 15 de CpcPaChi }

var
  i, j, k: byte;

procedure inicializa;
begin
  cpcMode (1);
  cpcInk(0,BLACK);
  cpcInk(1,WHITE);
  cpcInk(2,BRIGHTYELLOW);
  cpcInk(3,PALEYELLOW);
  paper(0);
end;

procedure lineaHorizontal;
begin
  for i := 1 to 10 do
    writeChar('*') ;
end;

(* Vamos a dibujar un cuadrado *)
begin

  inicializa;
  locate(2,2);
  writeString('Alla vamos...');

  locate(10,3);
  pen(1);
  lineaHorizontal;

  pen(2);
  for j := 4 to 7 do
    begin
    locate(10,j);
    writeChar('*');
    for k := 1 to 8 do
      writeChar(' ');
    writeChar('*');
    end;

  locate(10,8);
  pen(3);
  lineaHorizontal;

  locate(20,20);
  writeString('Hemos terminado!');
  pen(1);
end.</code></pre>


<p>que se ver&iacute;a:</p>

<img src="ej015.png" alt="eemplo15" /

<p><br />
  Como siempre, para m&aacute;s detalles, todo el c&oacute;digo est&aacute; en la p&aacute;gina del proyecto en Google Code:<br />
  <br />
  <a href="http://code.google.com/p/cpcpachi/">http://code.google.com/p/cpcpachi/</a></p>
<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>
</body>
</html>
